package fr.ece.ing4.demo.thread3;

import java.math.BigInteger;
import java.util.Observable;
import java.util.Observer;

import fr.ece.demo.threads2.Updatable;

/**
 * A simple class that implements a factorial calculation.
 * It is a pure logic (model) class and uses a FactorialApp class to display intermediate 
 * and final results for it. 
 * 
 * Note how it is encapsulated within the package (default package visibility).
 * 
 * Question for discussion : If I wanted to expose the Factorial logic 
 * independently of the supplied app, allowing other apps to call and be updated by it,
 * what changes would I have to make to the code?
 * 
 * @author Justin Templemore
 *
 */
class FactorialLogic extends Observable implements Runnable
{
	private Observer viewToUpdate;
	private long delayInMillis = 100;
	private long value;
	private BigInteger result;
	
	FactorialLogic (Observer viewToUpdate) 
	{
		this.viewToUpdate = viewToUpdate;
		
	}
	
	FactorialLogic () 
	{
		
	}
	
	
	public FactorialLogic(Observer viewToUpdate, long value) {
		this(viewToUpdate);
		this.value = value;
	}
	
	public void setValue(long value) {
		this.value = value;
	}
	
	/**
	 * Sets the delay (in milliseconds) between each successive iteration of the calculation.
	 * Purely for debugging and testing purposes. Not for production.
	 * @param delayInMillis delay in milliseconds
	 */
	void setDelayInMillis (long delayInMillis) {
		this.delayInMillis = delayInMillis;
	}
	
	BigInteger calculate (long value)
	{
		BigInteger result = new BigInteger ("1");
		ValueBean vb = new ValueBean();
		vb.setFinal(false);
		for (int i = 1; i <= value; i++)
		{
			try { Thread.sleep (this.delayInMillis); } catch (InterruptedException e) { }		// slow down calc for intermediate display
			result = result.multiply (new BigInteger (""+i));
			System.out.println (result);										// debug
			/*
			 * Note how the intermediate results are never displayed by Swing (but are clearly 
			 * calculated, as shown on the console)! This is because the 
			 * Swing event thread, which updates the display, is busy doing the calculation.
			 * Only at the END of this calculation will the Swing event thread be able to
			 * update the display. To do both at the same time, you need a new thread.
			 */
			//viewToUpdate.displayIntermediateValue(result);
			vb.setValue(result);
			setChanged();
			//System.out.println("Avant Intermediaire");
			notifyObservers(vb);
			//System.out.println("Après Intermédiaire");
			
		}
		//viewToUpdate.displayFinalValue(result);
		vb.setFinal(true);
		setChanged();
		notifyObservers(vb);
		return result;
	}

	public void run() {
		this.result = calculate(value);
		
	}

	public BigInteger getResult() {
		return result;
	}
}
